﻿using System;
using System.ComponentModel.Composition;
using Cubicle.Core.Interfaces;

namespace Cubicle.Core.Processors.Construct
{
    [Export("Cubicle.Processors.Construct.JaggedArrayConstructProcessor", typeof(IProcessor<InstructionRequest>))]
    [ExportMetadata("Name", "JaggedArrayConstructProcessor")]
    [ExportMetadata("Description", "Creates jagged arrays")]
    public class JaggedArrayConstructProcessor : InstructionRequestProcessor
    {

        #region Overrides of Processor<InstructionRequest>

        public JaggedArrayConstructProcessor() 
            : base(RequestType.CustomConstruct) { }

        public override bool Condition(InstructionRequest request)
        {
            var type = request.TargetType;
            return base.Condition(request) 
                && type.IsArray
                && type.GetArrayRank() == 1
                && type.GetElementType().IsArray;
        }

        public override InstructionRequest ConditionalProcess(InstructionRequest request)
        {
            // Find array type
            var elementType = request.TargetType.GetElementType();
            var arrayType = elementType.GetElementType();

            // Find size of first dimension
            var parameters = request.Inst.Parameters;
            var dimLength = parameters.GetLength(0);

            // Construct the jagged array
            var result = Array.CreateInstance(elementType, dimLength);
            int dimLength2;
            Array temp;
            for (int dim1 = 0; dim1 < dimLength; dim1++)
            {
                var arr = (Array) parameters[dim1];
                dimLength2 = arr.Length;
                result.SetValue(Array.CreateInstance(arrayType, dimLength2), dim1);

                // Initialise the values
                temp = (Array)result.GetValue(dim1);
                for (int dim2 = 0; dim2 < dimLength2; dim2++)
                    temp.SetValue(Convert.ChangeType(arr.GetValue(dim2), arrayType), dim2);
            }

            // Return the result
            request.Complete(result);
            return request;
        }

        #endregion
    }
}